using System;
using System.Collections.Generic;
//using System.Diagnostics;
using System.Threading;

namespace Monorf
{
   /// <summary>
   /// By  http://blogs.msdn.com/ploeh/archive/2007/02/09/AGenericIAsyncResultImplementation.aspx
   /// With a little modifications
   /// </summary>
   /// <typeparam name="T"></typeparam>
    internal class AsyncResult<T> : IAsyncResult, IDisposable
    {
        private readonly AsyncCallback m_callback;
        private bool m_completed;
        private bool m_completedSynchronously;
        private readonly object m_asyncState;
        private readonly ManualResetEvent m_waitHandle;
        private T m_result;
        private Exception m_myException;
        private readonly object m_syncRoot;


        internal AsyncResult(AsyncCallback cb, object state)
            : this(cb, state, false)
        {

        }

        internal AsyncResult(AsyncCallback cb, object state, bool completed)
        {
            this.m_callback = cb;
            this.m_asyncState = state;
            this.m_completed = completed;
            this.m_completedSynchronously = completed;
            this.m_waitHandle = new ManualResetEvent(false);
            this.m_syncRoot = new object();
        }

        #region IAsyncResult Members

        public object AsyncState
        {
            get { return this.m_asyncState; }
        }

        public WaitHandle AsyncWaitHandle
        {
            get { return this.m_waitHandle; }
        }

        public bool CompletedSynchronously
        {
            get
            {
                lock (this.m_syncRoot)
                {
                    return this.m_completedSynchronously;
                }
            }
        }

        public bool IsCompleted
        {
            get
            {
                lock (this.m_syncRoot)
                {
                    return this.m_completed;
                }
            }
        }

        #endregion


        #region IDisposable Members


        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                lock (this.m_syncRoot)
                {
                    if (this.m_waitHandle != null)
                    {
                        ((IDisposable)this.m_waitHandle).Dispose();
                    }
                }
            }
        }

        #endregion

        internal Exception Exception
        {
            get
            {
                lock (this.m_syncRoot)
                {
                    return this.m_myException;
                }
            }
        }

        internal T Result
        {
            get
            {
                lock (this.m_syncRoot)
                {
                    return this.m_result;
                }
            }
        }

        internal void Complete(T result, bool completedSynchronously)
        {
            lock (this.m_syncRoot)
            {
                this.m_completed = true;
                this.m_completedSynchronously = completedSynchronously;
                this.m_result = result;
            }

            this.SignalCompletion();
        }

        internal void HandleException(Exception e, bool completedSynchronously)
        {
            lock (this.m_syncRoot)
            {
                this.m_completed = true;
                this.m_completedSynchronously = completedSynchronously;
                this.m_myException = e;
            }

            this.SignalCompletion();
        }

        private void SignalCompletion()
        {
            this.m_waitHandle.Set();

            ThreadPool.QueueUserWorkItem(new WaitCallback(this.InvokeCallback));
        }

        private void InvokeCallback(object state)
        {
            if (this.m_callback != null)
            {
                this.m_callback(this);
            }
        }
    }
}

